#reader
import pc
import sexprs
    
def ParseQuote(qType,tag):
    ps = pc.ParserStack()
    ans = ps.parser(pc.pcWord(qType)) \
                .delayed_parser(lambda: pSexpr) \
                .catens(2) \
                .pack(lambda x: sexprs.Pair(sexprs.Symbol(tag) , sexprs.Pair(x[1],sexprs.Nil()))) \
                .done()
    return ans            
                        
        
ps = pc.ParserStack()

pSmallLetter = ps.parser(pc.pcOneOf('abcdefghijklmnopqrstuvwxyz')).pop()
pBigLetter = ps.parser(pc.pcOneOf('ABCDEFGHIJKLMNOPQRSTUVWXYZ')).pop()
pDigit = ps.parser(pc.pcOneOf('0123456789')).pop()
pDigitNoZero = ps.parser(pc.pcOneOf('123456789')).pop()
pPunctuation = ps.parser(pc.pcOneOf('!$^*-_=+<>/?')).pop()
#def pEverything(self):                           
pEverything = ps.const(lambda x: ord(x)>=0).pop()           
#def pWhite
pWhite = ps.const(lambda x: x<= ' ') \
            .pop()
#def pLineComment - ';' (pEverything\'\n') * '\n'
pLineComment = ps.parser(pc.pcWord(';')) \
            .parser(pEverything) \
            .parser(pc.pcWord('\n')) \
            .butNot() \
            .star() \
            .parser(pc.pcWord(chr(10))) \
            .catens(3) \
            .pop()
#def pSexprComment - '#;' pSexpr
pSexprComment = ps.parser(pc.pcWord('#;')) \
            .delayed_parser(lambda: pSexpr) \
            .catens(2) \
            .pop()
#def pSkip - (pWhite | pLineComment | pSexprComment) *
pSkip = ps.parser(pWhite) \
            .parser(pLineComment) \
            .parser(pSexprComment) \
            .disjs(3) \
            .star() \
            .pack(lambda x: '') \
            .pop()
#def pBoolean - '#t' | '#T' | '#f' | '#F'
pBoolean = ps.parser(pc.pcWord('#t')) \
            .parser(pc.pcWord('#T')) \
            .disjs(2) \
            .parser(pc.pcWord('#f')) \
            .parser(pc.pcWord('#F')) \
            .disjs(2) \
            .disjs(2) \
            .pack(lambda x: ''.join(x)) \
            .pack(lambda x: sexprs.Boolean(x)) \
            .pop()
#def pHexDigit
pHexDigit = ps.parser(pDigit) \
            .parser(pc.pcOneOf('ABCDEF')) \
            .pack(lambda x: x.lower()) \
            .parser(pc.pcOneOf('abcdef')) \
            .disjs(2) \
            .disjs(2) \
            .pop()
#def pHex  - ('0x' | '0H') pHexDigit+             
pHex = ps.parser(pc.pcWordCI('0x')) \
            .parser(pc.pcWordCI('0H')) \
            .disjs(2) \
            .parser(pHexDigit) \
            .plus() \
            .pack(lambda x: ''.join(x)) \
            .catens(2) \
            .pack(lambda x: int('0x'+x[1],16)) \
            .pop()
#def pNat - ('0'...'9') +            
pNat = ps.parser(pDigit) \
            .parser(pDigit) \
            .star() \
            .catens(2) \
            .pack(lambda x: x[0]+''.join(x[1])) \
            .pack(lambda x: int(x,10)) \
            .pop()
#def pUnsigned - pHex | pNat            
pUnsigned = ps.parser(pHex) \
            .parser(pNat) \
            .disjs(2) \
            .pop()
#def pSigned - '+'pUnsigned | '-'pUnsigned            
pSigned = ps.parser(pc.pcWord('+')) \
            .parser(pUnsigned) \
            .catens(2) \
            .parser(pc.pcWord('-')) \
            .parser(pUnsigned) \
            .pack(lambda x: -x) \
            .catens(2) \
            .disjs(2) \
            .pack(lambda x: x[1]) \
            .pop()
#def pInt - pSigned | pUnsigned            
pInt = ps.parser(pSigned) \
            .parser(pUnsigned) \
            .disjs(2) \
            .pack(lambda x: sexprs.Integer(x)) \
            .pop()
#def pHexDigitNoZero
pHexDigitNotZero = ps.parser(pDigitNoZero) \
            .parser(pc.pcOneOf('ABCDEF')) \
            .pack(lambda x: x.lower()) \
            .parser(pc.pcOneOf('abcdef')) \
            .disjs(2) \
            .disjs(2) \
            .pop()
#def pHexNoZero  - ('0x' | '0H') ('0')* pHexDigitNoZero pHexDigit*             
pHexNotZero = ps.parser(pc.pcWordCI('0x')) \
            .parser(pc.pcWordCI('0H')) \
            .disjs(2) \
            .parser(pc.pcWord('0')) \
            .star() \
            .parser(pHexDigitNotZero) \
            .parser(pHexDigit) \
            .star() \
            .catens(3) \
            .pack(lambda x: ''.join(x)) \
            .catens(2) \
            .pack(lambda x: int('0x'+x[1],16)) \
            .pop()
#def pNatNoZero - ('0')* ('1'...'9') ('0'...'9')*            
pNatNotZero = ps.parser(pc.pcWord('0')) \
            .star() \
            .parser(pDigit) \
            .parser(pDigitNoZero) \
            .star() \
            .catens(3) \
            .pack(lambda x: x[1]+''.join(x[2])) \
            .pack(lambda x: int(x,10)) \
            .pop()
#def pDenominator - pHexNoZero | pNatNoZero            
pDenominator = ps.parser(pHexNotZero) \
            .parser(pNatNotZero) \
            .disjs(2) \
            .pop()
#def pFraction - pInt '/' pDenominator            
pFraction = ps.parser(pInt) \
            .parser(pc.pcWord('/')) \
            .parser(pDenominator) \
            .catens(3) \
            .pack(lambda x: sexprs.Fraction(x[0],x[2])) \
            .pop()       
#def pNumber - pFraction | pInt      
pNumber = ps.parser(pFraction) \
            .parser(pInt) \
            .disjs(2) \
            .pop()
#def pSymbol - (pSmallLetter | pBigLetter | pPunctuation | pDigit) +
pSymbol = ps.parser(pPunctuation) \
            .parser(pBigLetter) \
            .parser(pSmallLetter) \
            .pack(lambda x: x.upper()) \
            .parser(pDigit) \
            .disjs(4) \
            .parser(pPunctuation) \
            .parser(pBigLetter) \
            .parser(pSmallLetter) \
            .pack(lambda x: x.upper()) \
            .parser(pDigit) \
            .disjs(4) \
            .star() \
            .catens(2) \
            .pack(lambda x: x[0]+''.join(x[1])) \
            .pack(lambda x: sexprs.Symbol(x)) \
            .pop()
#def pMetaChars - '\n' | '\r' | '\t' | '\f' | '\\' | '\"' | '\l' 
pMetaChars = ps.parser(pc.pcWord('\\n')) \
             .pack(lambda x: chr(10)) \
             .parser(pc.pcWord('\\r')) \
             .pack(lambda x: chr(13)) \
             .parser(pc.pcWord('\\t')) \
             .pack(lambda x: chr(9)) \
             .parser(pc.pcWord('\\f')) \
             .pack(lambda x: chr(12)) \
             .parser(pc.pcWord('\\\"')) \
             .pack(lambda x: '\\"') \
             .parser(pc.pcWord('\\l')) \
             .pack(lambda x: chr(0x03bb)) \
             .parser(pc.pcWord('\\\\')) \
             .pack(lambda x: chr(92)) \
             .disjs(7) \
             .pop()            
#def pString - '"' ( pMetaChars | pEverything\'"' )* '"'
pString = ps.parser(pc.pcWord('"')) \
            .parser(pMetaChars) \
            .parser(pEverything) \
            .parser(pc.pcWord('"')) \
            .butNot() \
            .disjs(2) \
            .star() \
            .pack(lambda x: ''.join(x)) \
            .parser(pc.pcWord('"')) \
            .catens(3) \
            .pack(lambda x: sexprs.String(x[1])) \
            .pop()                      
#def pNamedChar - 
pNamedChar = ps.parser(pc.pcWordCI('newline')) \
             .pack(lambda x: chr(10)) \
             .parser(pc.pcWordCI('return')) \
             .pack(lambda x: chr(13)) \
             .parser(pc.pcWordCI('tab')) \
             .pack(lambda x: chr(9)) \
             .parser(pc.pcWordCI('page')) \
             .pack(lambda x: chr(12)) \
             .parser(pc.pcWordCI('lambda')) \
             .pack(lambda x: chr(0x03bb)) \
             .disjs(5) \
             .pop()
#def pByte - pHexDigit pHexDigit
pByte = ps.parser(pHexDigit) \
             .parser(pHexDigit) \
             .catens(2) \
             .pack(lambda x: x[0]+''.join(x[1])) \
             .pop()            
#def pWord - pByte pByte
pWord = ps.parser(pByte) \
             .parser(pByte) \
             .catens(2) \
             .pack(lambda x: x[0]+''.join(x[1])) \
             .pop()             
#def pHexChar - 'x' pWord | pByte 
pHexChar = ps.parser(pc.pcWord('x')) \
             .parser(pWord) \
             .parser(pByte) \
             .disjs(2) \
             .catens(2) \
             .pack(lambda x: int('0x'+x[1],16)) \
             .pack(lambda x: chr(x)) \
             .pop()  
#def pVisChar - 
pVisChar = ps.const(lambda x: ord(x)>=33) \
             .pop()                                 
#def pChar - '#\' (pNamedChar | pHexChar | pVisChar)
pChar = ps.parser(pc.pcWord('#\\')) \
            .pack(lambda x: '#\\') \
            .parser(pNamedChar) \
            .parser(pHexChar) \
            .parser(pVisChar) \
            .disjs(3) \
            .catens(2) \
            .pack(lambda x: sexprs.Char(x[1])) \
            .pop()         
#def pProperList - '(' Sexpr * ')'
pProperList = ps.parser(pc.pcWord('(')) \
            .delayed_parser(lambda: pSexpr) \
            .star() \
            .parser(pc.pcWord(')')) \
            .catens(3) \
            .pack(lambda x: sexprs.CreateListOfPairs(x[1], sexprs.Nil())) \
            .pop()
#def pImProperList - '(' Sexpr + '.' Sexpr ')'
pImProperList = ps.parser(pc.pcWord('(')) \
            .delayed_parser(lambda: pSexpr) \
            .plus() \
            .parser(pc.pcWord('.')) \
            .delayed_parser(lambda: pSexpr) \
            .parser(pc.pcWord(')')) \
            .catens(5) \
            .pack(lambda x: sexprs.CreateListOfPairs(x[1], x[3])) \
            .pop()
#def pList - pProperList | pImProperList
pList = ps.parser(pProperList) \
            .parser(pImProperList) \
            .disjs(2) \
            .pop()
#def pVector - '#(' Sexpr * ')'
pVector = ps.parser(pc.pcWord('#(')) \
            .delayed_parser(lambda: pSexpr) \
            .star() \
            .parser(pc.pcWord(')')) \
            .catens(3) \
            .pack(lambda x: sexprs.Vector(x[1])) \
            .pop()
#def pNil - '(' pSkip ')'
pNil = ps.parser(pc.pcWord('(')) \
            .parser(pSkip) \
            .parser(pc.pcWord(')')) \
            .catens(3) \
            .pack(lambda x: sexprs.Nil()) \
            .pop()                     
#def pQuote - '#(' Sexpr * ')'
pQuote = ps.parser(ParseQuote('\'', "quote")) \
            .parser(ParseQuote(',', "unquote")) \
            .parser(ParseQuote(',@', "unquote-splicing")) \
            .parser(ParseQuote('`', "quasiquote")) \
            .disjs(4) \
            .pop()            
#def pSexpr - pSkip ( pBoolean | pNumber | pString | pChar | pNil | pList | pVector | pQuote | pSymbol ) pSkip                  
pSexpr = ps.parser(pSkip) \
            .parser(pBoolean) \
            .parser(pNumber) \
            .parser(pString) \
            .parser(pChar) \
            .parser(pNil) \
            .parser(pList) \
            .parser(pVector) \
            .parser(pQuote) \
            .parser(pSymbol) \
            .disjs(9) \
            .parser(pSkip) \
            .catens(3) \
            .pack(lambda x: x[1]) \
            .done()                                               